local math = math
local pairs = pairs
local ipairs = ipairs
local type = type
local table = table
local tabletool = require "tabletool"
local timetool = require "timetool"
local base = require "base"
local filelog = require "filelog"
require "enum"
require "dkgmjcardvalue"

local cardTool = {

}

local function getCard(value)
    local t = {}
    t.v = math.fmod(value, 10)  --value 1-9
    t.c = math.ceil(value/10)  --color 1,2,3,4,5,6
    return t
end
--判断是否缺一门
local function getQue(cards)
    local tmp = {}
    for k, v in pairs(cards) do
        tmp[v.c] = tmp[v.c] or {}
        table.insert(tmp[v.c], v)
    end
    return tmp
end
--形成花色牌组
local function genGroup(cards)
    local group = {
        [1] = {0,0,0,0,0,0,0,0,0},
        [2] = {0,0,0,0,0,0,0,0,0},
    }
    for k, v in pairs (cards) do
        group[v.c][v.v] = group[v.c][v.v] + 1
    end
    return group
end
--判断是否为5对
local function is5Pair(group)
    local cnt = 0
    for _,v in pairs(group) do
        for _, b in pairs(v) do
            if b > 0 then
                if b == 2 then
                    cnt = cnt + 1
                elseif b == 4 then
                    cnt = cnt + 2
                else
                    break
                end
            end
        end
    end
    return (cnt==5)
end

--判断是否为大对子(对对胡)
local function isBigPair(group)
    local two = 0
    local three = 0
    for _,v in pairs(group) do
        for _, b in pairs(v) do
            if b == 2 then
                two = two + 1
            elseif b == 3 then
                three = three + 1
            end
        end
    end
    return (three == 3 and two == 1)
end
--判断是否为将对
--注意：需要先判定为大对子才能使用此方法
local function isJiangdui(group)
    local t_match = {[2]=true,[5]=true,[8]=true}
    for _,v in pairs(group) do
        for a, b in pairs(v) do
            if b > 0 then
                if not t_match[a] then
                    return false
                end
            end
        end
    end
    return true
end
--判断是否为幺九
--注意：使用前须得确认能胡
--由牌型规律所得：非幺非九的牌张数应为2的整数倍，否则组不成幺九牌型
local function isYaoJiu(group)
    local t_match = {
        [1] = {match=1},
        [2] = {match=1},
        [3] = {match=1},
        [7] = {match=9},
        [8] = {match=9},
        [9] = {match=9}
    }
    for _,v in pairs(group) do
        for a, b in pairs(v) do
            if b > 0 then
                local tmp = t_match[a]
                if not tmp then
                    return false
                elseif v[tmp.match] < b then
                    return false
                end
            end
        end
    end
    return true
end

--判断是否断幺九
local function isDuanYaoJiu(cards)
    for k, v in pairs(cards) do
        if v.v == 1 or v.v == 9 then
            return false            
        end
    end
    return true
end
--判断是否为清一色
local function isQingYiSe(cards)
    local que = getQue(cards)
    local cnt = 0
    for k,v in pairs(que) do
        if #v > 0 then
            cnt = cnt + 1
        end
    end
    return (cnt == 1)
end

--组合胡牌牌型
local function comboHuTypes(types)
    local tmp = {}
    for k,v in pairs(types) do
        tmp[v.type] = v.cnt
    end
    local final = {}
    local function addType(name, cnt)
        local stType = {
            type = name,
            cnt = cnt,
        }
        table.insert(final, stType)
    end
    local genCnt = tmp.gen or 0
    
    if tmp["7dui"] and tmp.qingyise and tmp.gen >= 1 then
        --清龙七对
        addType("qinglong7dui", 1)
        genCnt = genCnt - 1
    elseif tmp["7dui"] and tmp.qingyise then
        --清七对
        addType("qing7dui", 1)
    elseif tmp.yaojiu and tmp.qingyise then
        --清幺九
        addType("qingyaojiu", 1)
    elseif tmp["7dui"] and tmp.gen > 0 then
        --龙七对
        addType("long7dui", 1)
        genCnt = genCnt - 1
    elseif tmp.dadui and tmp.qingyise then
        --清大对
        addType("qingdadui", 1)
    end
    if #final > 0 then
        if genCnt > 0 then
            addType("gen", genCnt)
        end
    else
        final = types
    end
    return final
end

--判断是否是一个搭子
local function checkDazi(split, canSplit)
    --print("checkDazi===", split)
    local function reverse(s)
        --[[
        local r = ""
        for i = #s, 1, -1 do
            r = r .. string.sub(s, i, i)
        end
        --print("reverse", r)
        return r
        --]]
        return string.reverse(s)
    end
    if t_dazi[tonumber(split)] or t_dazi[tonumber(reverse(split))] then
        --print("hs", split)
        return true
    else
        if #split == 1 or not canSplit then
            return false
        end
        for i=1, #split do
            local subSplit = string.sub(split, 0, i)
            if checkDazi(subSplit, false) then
                --print("sub", subSplit, string.sub(split, i+1))
                return checkDazi(string.sub(split, i+1), true)
            end
        end
        return false
    end
end
--判断单花色是否满足胡的条件
local function isColorCanHu(singleGroup)
    local function getColorCardNum(g)
        local num = 0
        for k, v in pairs(g) do
            num = num + v
        end
        return num
    end
    local cnt = getColorCardNum(singleGroup)

    local function isColorCanHu3x(g)
        --判断3x牌能否组成搭子
        --切割0xx0，看是否组成搭子
        local function splitGroup(t)
            local t_split = {}
            local tmp = ""
            for i=1, #t do
                if t[i] ~= 0 then
                    tmp = tmp .. t[i]
                    if i==9 then
                        table.insert(t_split, tmp)
                        tmp = ""
                    end
                else
                    if #tmp>0 then
                        table.insert(t_split, tmp)
                    end
                    tmp = ""
                end
            end
            return t_split
        end
        local s = splitGroup(g)
        for k, v in pairs(s) do
            if not checkDazi(v, true) then
                return false
            end
        end
        return true
    end
    --判断牌数，是否带将
    if math.fmod(cnt, 3) == 0 then
        return isColorCanHu3x(singleGroup)
    elseif math.fmod(cnt, 3) == 2 then
        --将大于2的牌都当作将遍历一遍，看其中是否有满足条件的类型
        --获取大于2的牌
        local t_jiang = {}
        for i=1, #singleGroup do
            if singleGroup[i]>=2 then
                table.insert(t_jiang, i)
            end
        end
        local function checkJiang(jiang_value)
            local tmp = {}
            for i=1, #singleGroup do
                if i~= jiang_value then
                    table.insert(tmp, singleGroup[i])
                else
                    table.insert(tmp, singleGroup[i]-2)
                end
            end
            if isColorCanHu3x(tmp) then
                return true
            else
                return false
            end
        end
        for i=1, #t_jiang do
            if checkJiang(t_jiang[i]) then
                return true
            end
        end
        return false
    else
        return false
    end
end

--判断是否能杠
--@values:手牌
--@card:判断被杠的牌
function cardTool.checkGang(values, card)
    local cnt = 0
    for i,v in ipairs(values) do
        if v == card then
            cnt = cnt + 1
        end
    end
    return (cnt == 3)
end

--判断是否能碰
--@values:手牌
--@card:判断被碰的牌
function cardTool.checkPeng(values, card)
    local cnt = 0
    for i,v in ipairs(values) do
        if v == card then
            cnt = cnt + 1
        end
    end
    return (cnt == 2) 
end

--判断是否能碰杠
--@values:手牌
--@card:判断被碰杠的牌
function cardTool.checkPengAndGang(values, card)
    local cnt = 0
    for i,v in ipairs(values) do
        if v == card then
            cnt = cnt + 1
        end
    end
    return cnt
end

--判断胡
function cardTool.checkHu(values)
    local cards = {}
    for i=1, #values do
        local card = getCard(values[i])
        table.insert(cards, card)
    end

    local group = genGroup(cards)

    --判断是否5对
    if is5Pair(group) then
        return true
    end

    --判断牌数量是否正确    
    if math.fmod(#values, 3) ~= 2 then
        return false
    end
    
    --按花色判断
    for k, v in pairs(group) do
        if not isColorCanHu(v) then
            return false
        end
    end
    return true
end

--取得玩家卡数
function cardTool.get_ka_num(hand, chumo_card, is_mopai)
    if #hand < 3 then
        return 0
    end

    if is_mopai then        
        for _, v in ipairs(hand) do
        end
    end
    for i=#hand, 1 do
        if hand[i] == chumo_card then
            table.remove(hand, i)
            break 
        end
    end

    for _, v in ipairs(hand) do

    end
end

--提示胡牌逻辑(传入的张数永远比胡牌少一张)
function cardTool.promptHu(values)
    local prompt = {}
    if math.fmod(#values, 3) ~= 1 then
        return prompt
    end
    
    --优化，优先判定是否缺，及缺哪门，减少遍历次数
    --判断是否打缺
    local cards = {}
    for i=1, #values do
        local card = getCard(values[i])
        table.insert(cards, card)
    end
    local que = getQue(cards)    
    for i,v in ipairs(t_value) do
        local card = getCard(v)
        if que[card.c] and math.fmod(#que[card.c], 3) ~= 0 then
            table.insert(values, v)
            if cardTool.checkHu(values) then
                table.insert(prompt, v)
            end
            table.remove(values, #values)
        end
    end
    return prompt
end

--判定玩家牌型
--可传入胡牌张数(用于判断胡牌牌型)，也可以传入比胡牌张数少一张(用于判断是否有叫或是请胡)
--di表示碰杠牌 hand表示玩家手牌 chumo_card表示玩家出或是摸的牌 is_mopai当前是否是摸牌 true表示摸牌, false表示出牌  
function cardTool.getTypes(di, hand, chumo_card, is_mopai)
    local types = {}
    local cards = {}
    for i=1, #di do
        local card = getCard(di[i])
        table.insert(cards, card)
    end
    for i=1, #hand do
        local card = getCard(hand[i])
        table.insert(cards, card)
    end
    table.sort(cards, function (a, b)
        if a.c == b.c then
            return a.v < b.v
        else
            return a.c < b.c
        end
    end)

    local function addType(name, cnt)
        local stType = {
            type = name,
            cnt = cnt,
        }
        table.insert(types, stType)
    end
    local que = getQue(cards)
    
    if not cardTool.checkHu(hand) then
        --不能胡，判定是否没叫
        local tmp = math.fmod(#hand, 3)
        if tmp == 1 then
            --判断是否有叫
            local prompt = cardTool.promptHu(hand)
            if #prompt == 0 then
                --没叫
                addType(EMJHuPaiType.HUPAI_TYPE_MEIJIAO, 0)
                return types
            else
                addType(EMJHuPaiType.HUPAI_TYPE_YOUJIAO, 0)
                return types
            end
        else
            return types
        end
    end
    
    local group = genGroup(cards)
    local is_jiangdui = false
    local is_5dui = false
    --判断是否5对
    if #di == 0 and #cards==10 then
        if is5Pair(group) then
            addType(EMJHuPaiType.HUPAI_TYPE_5DUIQINGHU, 1)
        end
    end
    --判断是否为对对胡(大对子)
    if isBigPair(group) and #cards==11 then
        if isJiangdui(group) then
            is_jiangdui = true
            addType(EMJHuPaiType.HUPAI_TYPE_JIANGDUI, 1)
        else
            addType(EMJHuPaiType.HUPAI_TYPE_DUIDUIHU, 1)
        end
    end

    --判断幺九
    if isYaoJiu(group) then
        addType(EMJHuPaiType.HUPAI_TYPE_DAIYAOJIU, 1)
    end
    --判断清一色
    if isQingYiSe(cards) then
        addType(EMJHuPaiType.HUPAI_TYPE_QINGYISE, 1)
    end

    if #types == 0 then
        addType(EMJHuPaiType.HUPAI_TYPE_PINGHU, 1)
    end

    --判断是否断1,9
    if not is_jiangdui and isDuanYaoJiu(cards) then
        addType(EMJHuPaiType.HUPAI_TYPE_DUANYAOJIU, 1)        
    end

    --获取勾数
    local genCnt = 0
    for i=1, #group do
        for k,v in pairs(group[i]) do
            if v == 4 then
                genCnt = genCnt + 1
            end
        end
    end
    if genCnt > 0 then
        addType(EMJHuPaiType.HUPAI_TYPE_GOU, genCnt)
    end

    --获取卡数
    if not is_5dui then
    end

    for k,v in pairs(types) do
        print(k, v.type, v.cnt)
    end
    types = comboHuTypes(types)
    return types
end

----------------------------------------------------《牌型控制工具函数》----------------------------
function cardTool.RandCardList()
      --混乱准备
    local cardBuffer = {};
    local tmpCardData = nil;
    local bufferCount = nil;

    tmpCardData = tabletool.deepcopy(CardData);
    bufferCount = #CardData;
    
    
    --混乱扑克
    local randCount = 1;
    local position = 1;

    --local tmp_seed = base.RNG()
    --if tmp_seed == nil then
    --    tmp_seed = timetool.get_10ms_time() + (seed or 0)
    --end
    
    local index
    local card1,card2
    for i=1,bufferCount do
        --math.randomseed(tmp_seed + 11*i)
        --index = math.random(bufferCount + 1 - i)
        index = base.get_random(1,bufferCount + 1 - i)
        card1 = tmpCardData[index]
        card2 = tmpCardData[bufferCount + 1 - i]
        tmpCardData[index],tmpCardData[bufferCount + 1 - i] = card2,card1
    end

    cardBuffer = tmpCardData
    --filelog.sys_error("cardBuffer->",cardBuffer)
    --filelog.sys_error("CardData->",CardData)
    
    return cardBuffer;
end

function cardTool.RandCardList_1(CardData)
      --混乱准备
    local cardBuffer = {};
    local tmpCardData = nil;
    local bufferCount = nil;

    tmpCardData = tabletool.deepcopy(CardData);
    bufferCount = #CardData;
    
    
    --混乱扑克
    local randCount = 1;
    local position = 1;

    --local tmp_seed = base.RNG()
    --if tmp_seed == nil then
     --   tmp_seed = timetool.get_10ms_time() + (seed or 0)
    --end
    
    local index
    local card1,card2
    for i=1,bufferCount do
        --math.randomseed(tmp_seed + 11*i)
        --index = math.random(bufferCount + 1 - i)
        index = base.get_random(1,bufferCount + 1 - i)
        card1 = tmpCardData[index]
        card2 = tmpCardData[bufferCount + 1 - i]
        tmpCardData[index],tmpCardData[bufferCount + 1 - i] = card2,card1
    end

    cardBuffer = tmpCardData
    --filelog.sys_error("cardBuffer->",cardBuffer)
    --filelog.sys_error("CardData->",CardData)
    
    return cardBuffer;
end
-- @des   判断万筒条
-- @author lion
function cardTool.JubCardType(card)

    if card <= 9 then
        return ColorType.Wan
    elseif card > 9 and card <= 19 then
        return ColorType.Tong
    elseif card > 19 and card <= 29 then
        return ColorType.Tiao
    end

    return -1
end

-- @des   删除牌
-- @author lion
function cardTool.delCards(srccards,cards)
    local num = 0
    for index = 1,#cards do
        local card = cards[index];
        if  cardTool.delCard(srccards,card) then
            num = num + 1
        end
    end
    return num
end

function cardTool.delCard(srccards,card)
    for index = 1,#srccards do
        local val = srccards[index];
        if val == card then
            table.remove(srccards,index);
            return true
        end
    end

    return false
end

-- @des   插入牌
-- @author lion
function cardTool.insCards(srccards,cards)
    for i=1,#cards do
        cardTool.insCard(srccards,cards[i]);
    end
end

function cardTool.insCard(srccards,card)
    table.insert(srccards,card);
end

-- @des   查找
-- @author lion
function cardTool.findCards(srccards,cards)
    local b = false;
    if (not srccards or not cards) then
        return b
    end
    
    for i=1,#cards do
        if (-1 ~= cardTool.findOneCard(srccards,cards[i])) then
            b = true;
            break;
        end
    end

    return b;
end

function cardTool.findOneCard(srccards,card)
    
    local rtn = -1
    for i = 1,#srccards do
        local src = srccards[i]
        if src  == card  then
            rtn = 1
            break
        end
    end

    return rtn
end

-- @des   拼接临时牌
-- @author lion
function cardTool.mosaicTempCards(srccards,cards)
    local tempCards = {}
    for k,v in pairs(srccards) do
        table.insert(tempCards,v)
    end
    for k,v in pairs(cards) do
        table.insert(tempCards,v)
    end

    return tempCards
end

--判断是否能碰杠 手中的牌
--@values:手牌
--@rtn true 手中有杠牌 false手中没有杠牌
function cardTool.checkPengSelf(values)
    
    local tempCardTypes = {}
    for i,v in ipairs(values) do
        if not tempCardTypes[v] then
            tempCardTypes[v] = {}
        end
        table.insert(tempCardTypes[v],v)
        if #tempCardTypes[v] == 4 then
            return true
        end
    end
    return false
end

-- @des   判断是否缺门
-- @author lion
-- @rtn true 缺门 false不缺门
function cardTool.jubIsQue(values,queColor)

    local cards = {}
    for i=1, #values do
        local card = getCard(values[i])
        table.insert(cards, card)
    end
    local que = getQue(cards)
    if que[queColor] and #que[queColor] > 0 then
        return true
    end
    return false
end


-- @des   判断有叫和没叫
-- @author lion
-- @rtn true 有叫 false没叫
function cardTool.jubIsYouJiao(handCards)
    
    local prompt = cardTool.promptHu(handCards)
    if #prompt == 0 then
        return false
    else
        return true
    end
    return false
end

-- @des   判断是不是中张牌
-- @author lion
function cardTool.isMenQinCard(cards)

    for i,card in ipairs(cards) do
      if card == 1 
        or card == 11 
        or card == 21
        or card == 9
        or card == 19
        or card == 29 then
            return false 
        end
    end

    return true
end

return cardTool
